﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;

using Tao.OpenGl;
using CutAways.Modeling;
using System.IO;
using CutAways.Illustration;
using CutAways.Geometry;

namespace CutAways
{
	partial class MainForm : Form
	{
		private ObjectBrowserForm objectBrowser;
		private PickObjectForm pickObjectForm;

		public MyGLControl MyGLControl
		{
			get { return this.myGLControl; }
		}

		public MainForm(string[] args)
		{
			InitializeComponent();
			this.objectBrowser = null;
			this.pickObjectForm = null;

			Shown += delegate { myGLControl.Initialize(); };
			FormClosed += delegate { myGLControl.DestroyContexts(); };

			SetProgramMode(ProgramMode.Start);

			//loadModelFromFile("../../modely/test.model");/**/
			if(args.Length > 0)
				loadModelFromFile(args[0]);
		}

		private void openToolStripMenuItem_Click(object sender, EventArgs e)
		{
			OpenFileDialog dialog = new OpenFileDialog();
			//dialog.InitialDirectory = Application.StartupPath;
			dialog.Filter = "All supported files|*.obj; *.model|OBJ files (*.obj) |*.obj|Model files (*.model) |*.model|All files (*.*)|*.*";
			dialog.FilterIndex = 0;
			if (dialog.ShowDialog() == DialogResult.OK)
				loadModelFromFile(dialog.FileName);
		}

		private void loadModelFromFile(string filename)
		{
			try
			{
				Model newModel = null;
				string extension = Path.GetExtension(filename).ToLower();
				switch (extension)
				{
					case ".obj":
						newModel = new ObjLoader().LoadFromFile(filename);
						break;
					case ".model":
						Stream streamRead = File.OpenRead(filename);
						BinaryFormatter binaryRead = new BinaryFormatter();
						newModel = (Model)binaryRead.Deserialize(streamRead);
						streamRead.Close();
						break;
					default:
						throw new NotSupportedException("This filetype is not supported.");
				}

                //setupLights();
				
				myGLControl.Model = newModel;
				this.Text = Path.GetFileName(filename) + " - Cut aways";
				if (objectBrowser != null)
					objectBrowser.Close();

				if (extension == ".model") // pokud nactu model, tak jdu rovnou do user modu
					SetProgramMode(ProgramMode.CutView);
				else // jinak mod ilustratora
					SetProgramMode(ProgramMode.Illustrator);
			}
			catch (ModelLoadingException ex)
			{
				showErrorMessage(ex.Message + Environment.NewLine + "(line number: " + ex.LineNumber + ")", "Model loading error");
			}
			catch (Exception ex)
			{
				showErrorMessage(ex.Message, "Error while loading model");
			}
		}

        private static void setupLights()
        {
            float[] ambient = { 0.4f, 0.4f, 0.4f, 1 };
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_AMBIENT, ambient);
            float[] diffuse = { 1, 1, 1, 1 };
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_DIFFUSE, diffuse);
            float[] specular = { 1, 1, 1, 1 };
            Gl.glLightfv(Gl.GL_LIGHT0, Gl.GL_SPECULAR, specular);
            float[] globalAmbient = { 0, 0, 0, 1 };
            Gl.glLightModelfv(Gl.GL_LIGHT_MODEL_AMBIENT, globalAmbient);
        }

		private void objectBrowserToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (objectBrowser == null)
			{
				objectBrowser = new ObjectBrowserForm(this);
				objectBrowser.FormClosed += delegate { objectBrowser = null; };
				//f.Change += delegate { myGLControl.Refresh(); };
				objectBrowser.Show();
			}
			else
			{
				objectBrowser.Focus();
			}
		}

		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			this.Close();
		}

		private void occlusiongraphToolStripMenuItem_Click(object sender, EventArgs e)
		{
			Cursor previousCursor = this.Cursor;
			this.Cursor = Cursors.WaitCursor;
			OcclusionGraph graph = null;
			try
			{
				graph = new OcclusionGraph(myGLControl.Model, myGLControl.Camera);
			}
			catch (Exception ex)
			{
				showErrorMessage(ex.Message, "Error while building occlusion graph");
				return;
			}
			finally
			{
				this.Cursor = previousCursor;
			}
			OcclusionGraphVisualizationForm form = new OcclusionGraphVisualizationForm(graph);
			form.ShowDialog(this);
		}

		private void showErrorMessage(string message, string caption)
		{
			MessageBox.Show(message, caption, MessageBoxButtons.OK, MessageBoxIcon.Error);
		}

		private void saveToolStripMenuItem_Click(object sender, EventArgs e)
		{
			SaveFileDialog dialog = new SaveFileDialog();
			//dialog.InitialDirectory = Application.StartupPath;
			dialog.Filter = "Model files (*.model) |*.model|All files (*.*)|*.*";
			dialog.FilterIndex = 0;
			if (dialog.ShowDialog() == DialogResult.OK)
				saveModelToFile(dialog.FileName);
		}

		private void saveModelToFile(string filename)
		{
			Stream streamWrite = File.Create(filename);
			try
			{
				BinaryFormatter binaryWrite = new BinaryFormatter();
				binaryWrite.Serialize(streamWrite, myGLControl.Model);
			}
			finally
			{
				streamWrite.Close();
			}
		}

		private void viewpointsToolStripMenuItem_Click(object sender, EventArgs e)
		{
			ModelViewpointsEditorForm form = new ModelViewpointsEditorForm(this.myGLControl);
			form.Show();
		}

		private void walkToolStripMenuItem_Click(object sender, EventArgs e)
		{
			if (myGLControl.ProgramMode == ProgramMode.CutView)
				 SetProgramMode(ProgramMode.Illustrator);
			else
				SetProgramMode(ProgramMode.CutView);
		}

		public void SetProgramMode(ProgramMode mode)
		{
			ProgramMode previous = myGLControl.ProgramMode;

			if (pickObjectForm != null)
				pickObjectForm.Close();
						
			if(previous == ProgramMode.CutView)
				myGLControl.ShadersSwitch(false);

			if (mode == ProgramMode.CutView && myGLControl.Model.ViewpointSet.Count == 0)
			{
				showErrorMessage("You must specify at least one viewpoint for model.", "Can't proceed");
				mode = ProgramMode.Illustrator;
			}

			// change mode
			myGLControl.ProgramMode = mode;
			
			switch (myGLControl.ProgramMode)
			{
				case ProgramMode.Start:
					objectBrowserToolStripMenuItem.Enabled = occlusiongraphToolStripMenuItem.Enabled = saveToolStripMenuItem.Enabled = viewpointsToolStripMenuItem.Enabled = walkToolStripMenuItem.Enabled = false;
					walkToolStripMenuItem.Checked = false;
					break;
				case ProgramMode.EditBoundingBox:
					objectBrowserToolStripMenuItem.Enabled = saveToolStripMenuItem.Enabled = true;
					occlusiongraphToolStripMenuItem.Enabled = viewpointsToolStripMenuItem.Enabled = walkToolStripMenuItem.Enabled = false;
					walkToolStripMenuItem.Checked = false;
					myGLControl.ResetView();
					break;
				case ProgramMode.Illustrator:
					objectBrowserToolStripMenuItem.Enabled = occlusiongraphToolStripMenuItem.Enabled = saveToolStripMenuItem.Enabled = viewpointsToolStripMenuItem.Enabled = walkToolStripMenuItem.Enabled = true;
					walkToolStripMenuItem.Checked = false;
					if (previous != ProgramMode.Illustrator && previous != ProgramMode.CutView)
						myGLControl.ResetView();
					break;
				case ProgramMode.CutView:
					objectBrowserToolStripMenuItem.Enabled = occlusiongraphToolStripMenuItem.Enabled = saveToolStripMenuItem.Enabled = viewpointsToolStripMenuItem.Enabled = false;
					walkToolStripMenuItem.Enabled = true;
					walkToolStripMenuItem.Checked = true;
					/**/ //myGLControl.ResetView();

					myGLControl.Walk();

					this.pickObjectForm = new PickObjectForm(myGLControl.Model);
					this.pickObjectForm.Pick += delegate
					{
						myGLControl.MoveToBestViewpointForSelectedObject(pickObjectForm.PickedObject);
					};
					this.pickObjectForm.FormClosed += delegate { this.pickObjectForm = null; };
					this.pickObjectForm.Show();

					break;
			}
		}
	}
}
